%{
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <stdbool.h>
    #include "predicate.h"
%}

%union {
    int i;
    int l;
    bool b;
    struct astree *ast;
    struct varname *vn;
    struct arguments *argm;
    char *str;
}

%token EOS PRINT DEF FIN IF ELSE FI 

%token <str> STRING
%token <i> INTEGER
%token <l> LOGICAL
%token <vn> IDENTIFIER FUNCTION

%type <argm> arguments
%type <b> condition
%type <ast> expression statement statement_group

%right '='
%left '+' '-'
%left '*' '/'
%left '%'
%nonassoc UNARY_MINUS

%start predicate

%%

expression: expression '+' expression { $$ = build_ast($1, $3, '+'); }
| expression '-' expression { $$ = build_ast($1, $3, '-'); }
| expression '*' expression { $$ = build_ast($1, $3, '*'); }
| expression '/' expression { $$ = build_ast($1, $3, '/'); }
| expression '%' expression { $$ = build_ast($1, $3, '%'); }
| '(' expression ')' { $$ = $2; }
| '-' expression %prec UNARY_MINUS { negate_ast($2); }
| INTEGER { $$ = init_number($1); }
| IDENTIFIER { $$ = symbol_to_expression($1); }
| IDENTIFIER '(' arguments ')' { $$ = function_call($1, $3); }
;

statement_group: statement statement_group
| statement
;


arguments: IDENTIFIER arguments { $$ = bind_arguments($1, $2); }
| IDENTIFIER { $$ = bind_arguments($1, NULL); }
;

statement: expression EOS { $$ = $1; }
| IDENTIFIER '=' statement { assignment($1, $3); }
| PRINT statement { printf("%d\n", evaluate_ast($2)); }
| IF '(' condition ')' ':' statement_group FI { $$ = evaluate_condition($3, $6, NULL); }
| IF '(' condition ')' ':' statement_group ELSE ':' statement_group FI { $$ = evaluate_condition($3, $6, $9); }
;

condition: expression LOGICAL expression { $$ = init_condition($1, $2, $3); }
;

function_definition: DEF IDENTIFIER '(' IDENTIFIER ')' ':' statement_group FIN { define_function($2, $4, $7); }
;

predicate: /* empty */
| predicate statement
| predicate function_definition
;

%%
